﻿// Jinx AJAX Framework
// Copyright (C) 2008 Blake Hegerle
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Linq;
using System.Text;
using Formality.FormalSystem.Parser;
using Formality;
using Core;

namespace Formality.FormalSystem
{
    public enum StringingStyle
    {
        Default,
        Detailed
    }

    public static class Stringers
    {
        public static string FunctionStringer(this Proposition f, Proposition Parent, StringingStyle Style)
        {
            var Func = new Function(f);

            var Name = Func.Name.ToString(Style);

            if (Func.Predicative)
                Name += Proposition.PF_OP;

            var Arguments = (from a in Func.Arguments select a.ToString(Style)).Join(", ");

            if (Func.Arguments.Length > 1)
                return string.Format("{0}({1})", Name, Arguments);

            if (Func.Arguments.Length == 1)
                return string.Format("{0}{1}", Name, Arguments);

            return Name;
        }

        public static string BinderStringer(this Proposition b, Proposition Parent, StringingStyle Style)
        {
            var Binder = new Binder(b);

            var Buffer = new StringBuilder();

            Buffer.Append(Binder.Operator);
            Buffer.Append(Binder.Variable.ToString(Style));

            foreach (var s in Binder.Scopes)
                Buffer.AppendFormat(" {0}", s.Stringer(s, b, Style));
            return Buffer.ToString();
        }

        public static string InfixStringer(this Proposition i, Proposition Parent, StringingStyle Style)
        {
            var Joiner = " " + i.Operator + " ";

            var OpStrings = (from op in i.Operands select op.Stringer(op, i, Style)).ToArray();

            var Left = OpStrings.Length - 1;
            var ThisString = OpStrings.Take(Left).Join(", ") + Joiner + OpStrings[Left];

            if (Parent != null)
            {
                Func<Proposition, int?> GetPrecedence = p =>
                {
                    var Op =
                        PropositionParser.Instance.PrecedenceRules.
                            TryGetOperator(p.Operator);

                    return Op != null ? Op.Precedence : (int?)null;
                };

                var ParentPrecedence = GetPrecedence(Parent);
                var MyPrecedence = GetPrecedence(i);

                if (MyPrecedence.HasValue == false)
                    MyPrecedence = int.MaxValue;

                var NeedsParen = (!ParentPrecedence.HasValue) || (ParentPrecedence.Value >= MyPrecedence.Value);

                if (NeedsParen)
                    ThisString = "(" + ThisString + ")";
            }

            return ThisString;
        }

        public static string PrefixStringer(this Proposition p, Proposition Parent, StringingStyle Style)
        {
            var Operand = p.Operands.Single();

            return p.Operator + Operand.Stringer(Operand, p, Style);
        }
    }
}
